package com.ruoyi.asset.park.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.asset.common.scopecode.constant.ServiceCode;
import com.ruoyi.asset.common.scopecode.service.IScopeCodeService;
import com.ruoyi.asset.homepage.constant.CommunityConstant;
import com.ruoyi.asset.homepage.constant.ServiceTypeConstant;
import com.ruoyi.asset.park.constant.ParkDirtConstant;
import com.ruoyi.asset.park.domain.ParkMaintenance;
import com.ruoyi.asset.park.domain.bo.*;
import com.ruoyi.asset.park.domain.vo.ParkCommunityCountVo;
import com.ruoyi.asset.park.domain.vo.ParkCommunityMapVo;
import com.ruoyi.asset.park.domain.vo.ParkMaintenanceVo;
import com.ruoyi.asset.park.domain.vo.ParkWorkStatisticsVo;
import com.ruoyi.asset.park.mapper.ParkMaintenanceMapper;
import com.ruoyi.asset.park.service.IParkMaintenanceService;
import com.ruoyi.asset.tool.domain.bo.ToolStatisticsBo;
import com.ruoyi.asset.tool.service.IToolService;
import com.ruoyi.asset.workman.service.IWorkmanService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.tools.excel.MyExcelUtil;
import com.ruoyi.common.tools.excel.base.MyExcelResult;
import com.ruoyi.common.tools.excel.listener.asset.ParkMaintenanceExcelListener;
import com.ruoyi.common.tools.utils.SerialGenerator;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.erecord.region.service.IRegionService;
import com.ruoyi.standingbook.park.service.IParkService;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 公园管养管养范围Service业务层处理
 *
 * @author lq
 * @date 2023-11-30
 */
@RequiredArgsConstructor
@Service
public class ParkMaintenanceServiceImpl implements IParkMaintenanceService {

	private final ParkMaintenanceMapper baseMapper;
	private final IWorkmanService workmanService;
	private final IToolService toolService;
    private final ISysDictDataService sysDictDataService;
    private final IRegionService regionService;
    private final IScopeCodeService scopeCodeService;
    private final IParkService parkService;

	private Boolean batchInsertOrUpdate(List<ParkMaintenance> voList) {
		return this.baseMapper.insertOrUpdateBatch(voList);
	}

	@Override
	public List<String> importExcel(String excelUrl) {
		List<String> errorMsgList = new ArrayList<>();

		// 生成批次号
		final String batchNo = SerialGenerator.generator.nextId();

		// excel 处理
		MyExcelResult<ParkMaintenanceVo> excelResult = MyExcelUtil.getImportExcelData(batchNo, excelUrl,
				new ParkMaintenanceExcelListener(batchNo), ParkMaintenanceVo.class, true);

		if (null == excelResult) {
			errorMsgList.add("未获取到要处理的数据");

			return null;
		}

        /**
         *  有解析失败就直接返回错误信息
         */
        if(!excelResult.getErrorList().isEmpty()) {
            return excelResult.getErrorList();
        }

		if (!excelResult.getList().isEmpty()) {
            List<ParkMaintenance> list = new ArrayList<>();

            AtomicInteger row = new AtomicInteger(0);

			excelResult.getList().forEach(e -> {
                int currentRow = row.incrementAndGet();
				if (e.getDataCheckResult().isSucess()) {
					ParkMaintenance parkMaintenance = new ParkMaintenance();

					BeanCopyUtils.copy(e, parkMaintenance);

					ParkMaintenance oldParkMaintenance = getVoByNameAndType(parkMaintenance.getParkName(),
							parkMaintenance.getMaintenanceType());

					if (oldParkMaintenance != null) {
						parkMaintenance.setId(oldParkMaintenance.getId());
					} else {
                        String scopeCode = null;

                        try {
                            scopeCode = scopeCodeService.getNextScopeCode(ServiceCode.PARK,
                                parkMaintenance.getMaintenanceType(), "");
                        } catch (Exception ex) {
                            errorMsgList.add("获取管理范围编码失败，失败原因：" + ex.getMessage());
                        }

                        parkMaintenance.setParkCode(scopeCode);
                    }

                    /**
                     *  如果各行数据校验通过，再遍历检查是否数据重复
                     */
                    if(excelResult.getValidateList().isEmpty()) {
                        AtomicInteger count = new AtomicInteger(0);
                        list.stream().anyMatch(f -> {
                            int currentCount = count.incrementAndGet();
                            if(f.getParkName().equals(parkMaintenance.getParkName()) && f.getMaintenanceType().equals(parkMaintenance.getMaintenanceType())) {
                                errorMsgList.add(String.format("第 %d 行数据检查失败，失败原因：与第%d行数据重复", currentRow, currentCount));
                                return true;
                            }
                            return false;
                        });
                    }

					list.add(parkMaintenance);
				} else {
					errorMsgList.add(String.format("第 %d 行数据检查失败，失败原因：%s", currentRow, e.getDataCheckResult().getMsg()));
				}
			});

			if (errorMsgList.isEmpty()) {
				batchInsertOrUpdate(list);
			}
		}

		return errorMsgList;
	}

	private ParkMaintenance getVoByNameAndType(String parkName, String maintenanceType) {
        LambdaQueryWrapper<ParkMaintenance> lqw = Wrappers.lambdaQuery();

        lqw.eq(ParkMaintenance::getParkName, parkName);
        lqw.eq(ParkMaintenance::getMaintenanceType, maintenanceType);
        lqw.eq(ParkMaintenance::getDelFlag, 0);

        List<ParkMaintenance> list = baseMapper.selectList(lqw);

        return list.isEmpty() ? null : list.get(0);
	}

	@Override
	public int deleteMaintenanceScope(Set<Long> idsSet) {
		if (CollectionUtils.isEmpty(idsSet)) {
			return -1;
		}

		return baseMapper.logicDeleteMaintenanceScope(idsSet);
	}

	@Override
	public TableDataInfo<ParkMaintenanceVo> queryMaintenanceScope(ParkMaintenanceSearchBo searchBo, PageQuery pageQuery) {
		Page<ParkMaintenanceVo> result = baseMapper.selectMaintenanceScopeWithPage(pageQuery.build(), searchBo);
        return TableDataInfo.build(result);
	}

	@Override
	public List<ParkMaintenanceVo> queryMaintenanceScope(ParkMaintenanceSearchBo searchBo) {
		return baseMapper.exportMaintenanceScope(searchBo);
	}

	@Override
	public ParkMaintenanceOverviewBo getParkMaintenanceOverview() {
		ParkMaintenanceOverviewBo statisticsBo = new ParkMaintenanceOverviewBo();
        Double parkArea = baseMapper.getParkArea();
        if (null != parkArea) {
            statisticsBo.setArea(parkArea);
        } else {
            statisticsBo.setArea(0.00);
        }
        Integer parkCount = baseMapper.getParkCount();
        statisticsBo.setParkCount(parkCount);
        int workCount = workmanService.getByServiceType(ServiceTypeConstant.PARK);
        statisticsBo.setWorkerCount(workCount);

        ToolStatisticsBo toolStatisticsBo = toolService.getCountByServiceType(ServiceTypeConstant.PARK);
        if (null != toolStatisticsBo) {
            statisticsBo.setEquipmentCount(toolStatisticsBo.getToolCount());
            statisticsBo.setVehicleCount(toolStatisticsBo.getVehicleCount());
        } else {
            statisticsBo.setEquipmentCount(0);
            statisticsBo.setVehicleCount(0);
        }

		return statisticsBo;
	}

	@Override
	public List<StatisticianParkByRegion> statForParkByRegion() {
		List<StatisticianParkByRegion> list = baseMapper.statForParkByRegion();

		list.forEach(item->{
			ToolStatisticsBo toolStat = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.PARK,
					item.getCommunityId());

			item.setEquipmentCount(toolStat.getToolCount());
			item.setVehicleCount(toolStat.getVehicleCount());

			int workCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.PARK,
					item.getCommunityId());
			item.setWorkerCount(workCount);
		});

        return list;
	}

    @Override
    public Map getParkCommunityCount() {
        HashMap<String, ParkCommunityBo> map = new HashMap<>();
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
        for (SysDictData community : data) {
            String communityNo = regionService.getRegionIdByName(community.getDictLabel());
            Integer parkNameCount = baseMapper.getParkNameCommunityCount(communityNo);
            List<ParkTypeBo> parkTypeBoList = baseMapper.getParkTypeCommunityCount(communityNo);
            parkTypeBoList.forEach(e->{
                String parkType = sysDictDataService.selectDictLabel(ParkDirtConstant.PARK, e.getMaintenanceType());
                if (StringUtils.isNotBlank(parkType)){
                    e.setMaintenanceType(parkType);
                }
            });
            ParkCommunityBo parkCommunityBo = new ParkCommunityBo();
            parkCommunityBo.setParkNameCount(parkNameCount);
            parkCommunityBo.setParkTypeBoList(parkTypeBoList);
            ToolStatisticsBo toolCount = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.PARK, communityNo);
            parkCommunityBo.setToolCount(toolCount.getToolCount());
            parkCommunityBo.setVehicleCount(toolCount.getVehicleCount());
            int workmanCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.PARK, communityNo);
            parkCommunityBo.setWorkmanCommunity(workmanCount);
            map.put(community.getDictLabel(), parkCommunityBo);
        }

        return map;
    }

    @Override
    public List<ParkCommunityCountVo> getParkCountByCommunity(String date) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<ParkCommunityCountVo> parkCommunityCountVos = new ArrayList<>();
        communities.forEach(e->{
            ParkCommunityCountVo parkCommunityCountVo = new ParkCommunityCountVo();
            parkCommunityCountVo.setCommunity(e.getDictLabel());
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            Integer parkNumSum = baseMapper.selectParkNumByCommunity(date,regionId);
            parkCommunityCountVo.setNumSum(parkNumSum.toString());
            Double parkAreaSum = baseMapper.selectParkAreaByCommunity(date, regionId);
            if (null != parkAreaSum) {
                parkCommunityCountVo.setAreaSum(parkAreaSum.toString());
            } else {
                parkCommunityCountVo.setAreaSum("0.00");
            }
            ToolStatisticsBo toolCount = toolService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.PARK, regionId,date);
            if (null != toolCount) {
                parkCommunityCountVo.setEquipmentCount(toolCount.getToolCount());
                parkCommunityCountVo.setVehicleCount(toolCount.getVehicleCount());
            } else {
                parkCommunityCountVo.setEquipmentCount(0);
                parkCommunityCountVo.setVehicleCount(0);
            }
            int workmanCount = workmanService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.PARK, regionId,date);
            parkCommunityCountVo.setWorkerCount(workmanCount);
            parkCommunityCountVos.add(parkCommunityCountVo);
        });

        return parkCommunityCountVos;
    }

    @Override
    public ParkCommunityMapVo getCommunityByDate(String community, String date) {
        ParkCommunityMapVo parkCommunityMapVo = new ParkCommunityMapVo();
        String communityNo = regionService.getRegionIdByName(community);
        Integer parkNumSum = baseMapper.selectParkNumByCommunity(date,communityNo);
        parkCommunityMapVo.setNumSum(parkNumSum.toString());
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(ParkDirtConstant.PARK);
        List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
        HashMap<String, String> map = new HashMap<>(32);
        List<ParkTypeBo> parkTypeBos = baseMapper.selectByCommunityAndDateCount(communityNo, date);
        buildLampTypeMap(data,parkTypeBos,map);
        parkCommunityMapVo.setParkTypeMap(map);
        ToolStatisticsBo toolCount = toolService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.PARK, communityNo,date);
        if (null != toolCount) {
            parkCommunityMapVo.setToolCount(toolCount.getToolCount());
            parkCommunityMapVo.setVehicleCount(toolCount.getVehicleCount());
        } else {
            parkCommunityMapVo.setVehicleCount(0);
            parkCommunityMapVo.setVehicleCount(0);
        }
        int workmanCount = workmanService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.PARK, communityNo,date);
        parkCommunityMapVo.setWorkmanCommunity(workmanCount);
        return parkCommunityMapVo;
    }

    @Override
    public ParkWorkStatisticsVo getParkWorkByDate(String date) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        List<Double> areaSumList = new ArrayList<>();
        communities.forEach(e-> {
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            Double parkAreaSum = baseMapper.selectParkAreaByCommunity(date, regionId);
            if (null != parkAreaSum) {
                areaSumList.add(parkAreaSum);
            } else {
                areaSumList.add(0.00);
            }
        });
        ParkWorkStatisticsVo parkWorkStatisticsVo = new ParkWorkStatisticsVo();
        BigDecimal parkAreaSum = BigDecimal.ZERO;
        if (areaSumList.size() > 0) {
            parkAreaSum = BigDecimal.valueOf(areaSumList.stream().reduce(Double::sum).orElse(0.00));
            parkWorkStatisticsVo.setTotalArea(parkAreaSum.toString());
        } else {
            parkWorkStatisticsVo.setTotalArea("0");
        }
        BigDecimal sumByDate = parkService.getAreaSumByDate(date);
        parkWorkStatisticsVo.setFinishedAreaSum(sumByDate.toString());
        if (sumByDate.compareTo(BigDecimal.ZERO)<=0 || parkAreaSum.compareTo(BigDecimal.ZERO)<=0){
            parkWorkStatisticsVo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = sumByDate.divide(parkAreaSum,2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            parkWorkStatisticsVo.setPercent(pec);
        }
        return parkWorkStatisticsVo;
    }

    @Override
    public ParkWorkStatisticsVo getParkWorkByDateAndCommunity(String date, String community) {
        ParkWorkStatisticsVo parkWorkStatisticsVo = new ParkWorkStatisticsVo();
        String regionId = regionService.getRegionIdByName(community);
        BigDecimal parkAreaSum = BigDecimal.ZERO;
        Double areaSum = baseMapper.selectParkAreaByCommunity(date, regionId);
        if (null != areaSum){
            parkAreaSum = BigDecimal.valueOf(areaSum);
        }
        parkWorkStatisticsVo.setTotalArea(parkAreaSum.toString());
        BigDecimal sumByDate = parkService.getAreaSumByDateAndCommunity(date,community);
        parkWorkStatisticsVo.setFinishedAreaSum(sumByDate.toString());
        if (sumByDate.compareTo(BigDecimal.ZERO)<=0 || parkAreaSum.compareTo(BigDecimal.ZERO)<=0){
            parkWorkStatisticsVo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = sumByDate.divide(parkAreaSum,2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            parkWorkStatisticsVo.setPercent(pec);
        }
        return parkWorkStatisticsVo;
    }

    @Override
    public ParkCommunityCountVo getParkByDateAndAndCommunity(String date, String community) {
        Integer num ;
        Double area ;
        ParkCommunityCountVo parkCommunityCountVo = new ParkCommunityCountVo();
        if (StringUtils.isNotEmpty(community)) {
            String regionId = regionService.getRegionIdByName(community);
             num = baseMapper.selectParkNumByCommunity(date, regionId);
             area = baseMapper.selectParkAreaByCommunity(date, regionId);
        } else {
            num = baseMapper.selectParkNumByCommunity(date, null);
            area = baseMapper.selectParkAreaByCommunity(date, null);
        }
        if (null == num) {
            num = 0;
        }
        if (null == area) {
            area = 0d;
        }
        parkCommunityCountVo.setNumSum(num.toString());
        parkCommunityCountVo.setAreaSum(area.toString());
        return parkCommunityCountVo;
    }

    /**
     * 组装数据
     * @param data
     * @param parkTypeBos
     * @param map
     */
    private void buildLampTypeMap(List<SysDictData> data, List<ParkTypeBo> parkTypeBos, HashMap<String, String> map){
        ArrayList<String> typeName = new ArrayList<>();
        for (SysDictData parkType : data) {
            if (parkTypeBos.size() > 0) {
                for (ParkTypeBo parkTypeBo: parkTypeBos) {
                    if (parkType.getDictValue().equals(parkTypeBo.getMaintenanceType())) {
                        typeName.add(parkType.getDictLabel());
                        map.put(parkType.getDictLabel(),parkTypeBo.getParkArea() + " ");
                    }
                }
            } else {
                map.put(parkType.getDictLabel(),"0");
            }
        }
        if (typeName.size() > 0) {
            List<String> labelList = data.stream().map(SysDictData::getDictLabel).collect(Collectors.toList());
            labelList.removeAll(typeName);
            labelList.forEach(e->{
                map.put(e,"0");
            });
        }
    }
}
